package com.kgc.storeprovider.service.impl;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.pagehelper.PageHelper;
import com.kgc.basic.pojo.BOM;
import com.kgc.basic.pojo.Good;
import com.kgc.basic.util.PageInfo;
import com.kgc.basic.util.ResponseMsg;
import com.kgc.store.pojo.*;
import com.kgc.storeprovider.dao.*;
import com.kgc.storeprovider.feign.BOMFeign;
import com.kgc.storeprovider.feign.SalesCounterFeign;
import com.kgc.storeprovider.service.ProCombineService;
import com.kgc.storeprovider.service.StoreGoodSummaryService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;

@Service
@Transactional
public class ProCombineServiceImpl implements ProCombineService {
    private Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private ProCombineMapper proCombineMapper;
    @Autowired
    private BOMFeign bomFeign;
    @Autowired
    private SalesCounterFeign salesCounterFeign;
    @Autowired
    private OutStoreMapper outStoreMapper;
    @Autowired
    private OutStoreDetailMapper outStoreDetailMapper;
    @Autowired
    private StoreGoodSummaryMapper storeGoodSummaryMapper;
    @Autowired
    private InStoreMapper inStoreMapper;
    @Autowired
    private InStoreDetailMapper inStoreDetailMapper;

    @Override
    public ResponseMsg getByPage(Map<String, Object> map) {
        logger.info("ProCombineServiceImpl getByPage map={}", map);
        ResponseMsg responseMsg = new ResponseMsg();
        PageHelper.startPage(Integer.parseInt(map.get("pageNow").toString()), Integer.parseInt(map.get("pageSize").toString()));
        List<ProCombine> list = proCombineMapper.getAll(map);
        logger.debug("proCombineMapper getAll list={}", list+",map"+map);
        PageHelper.clearPage();
        PageInfo<ProCombine> pageInfo = new PageInfo<>();
        if (list != null && list.size() > 0) {
            for (ProCombine proCombine : list) {
                ResponseMsg response = bomFeign.getBOMById(proCombine.getBid()+"");
                logger.debug("bomFeign.getBOMById={}", response+",id="+proCombine.getBid());
                if (response.getCode().equals("200")) {
                    ObjectMapper objectMapper = new ObjectMapper();
                    BOM bom = objectMapper.convertValue(response.getData(), BOM.class);
                    proCombine.setBname(bom.getName());
                    proCombine.setPname(bom.getProduct().getName());
                }
            }
            pageInfo.setList(list);
            pageInfo.setPageNo(Integer.parseInt(map.get("pageNow").toString()));
            pageInfo.setPageSize(Integer.parseInt(map.get("pageSize").toString()));
            pageInfo.setTotal(proCombineMapper.getCount(map));
            logger.debug("proCombineMapper.getCount list={}", pageInfo.getTotal()+",map"+map);
        }
        if (pageInfo.getTotal() > 0) {
            responseMsg.setCode("200");
            responseMsg.setData(pageInfo);
        }else {
            responseMsg.setCode("201");
        }
        return responseMsg;
    }

    @Override
    public ResponseMsg add(ProCombine proCombine) {
        logger.info("ProCombineServiceImpl add proCombine={}", proCombine);
        ResponseMsg responseMsg = new ResponseMsg();
        proCombine.setCreateDate(new Date());
//        proCombine.setCreateUser("admin");
        proCombine.setUpdateDate(new Date());
//        proCombine.setUpdateUser("admin");
        proCombine.setStatus("1");
        int count = proCombineMapper.add(proCombine);
        logger.debug("proCombineMapper.add count={}", count+",proCombine"+proCombine);
        if(count==0){
            responseMsg.setCode("201");
            return responseMsg;
        }
        Map<String,Object> map = new HashMap<>();
        map.put("code",proCombine.getCode());
        map.put("updateDate",proCombine.getUpdateDate());
        map.put("updateUser",proCombine.getUpdateUser());
        Long bid = proCombine.getBid();
        BOM bom = null;
        ResponseMsg response = bomFeign.getBOMById(bid+"");
        logger.debug("bomFeign.getBOMById={}", response+",bid="+bid);
        if (response.getCode().equals("200")) {
            ObjectMapper objectMapper = new ObjectMapper();
            bom = objectMapper.convertValue(response.getData(), BOM.class);
        }
        if(bom==null){
            throw new  RuntimeException();
        }
        boolean flag = addDetail(proCombine,bom,map);
        if(flag){
            responseMsg.setCode("200");
        }else {
            responseMsg.setCode("201");
        }
        return responseMsg;
    }

    @Override
    public ResponseMsg update(ProCombine proCombine) {
        logger.info("ProCombineServiceImpl update proCombine={}", proCombine);
        ResponseMsg responseMsg = new ResponseMsg();
        proCombine.setUpdateDate(new Date());
        int count = proCombineMapper.update(proCombine);
        logger.debug("proCombineMapper update count={}", count+",proCombine"+proCombine);
        if(count==0){
            responseMsg.setCode("201");
            return responseMsg;
        }
        Map<String,Object> map = new HashMap<>();
        map.put("code",proCombine.getCode());
        Long bid = proCombine.getBid();
        BOM bom = null;
        ResponseMsg response = bomFeign.getBOMById(bid+"");
        logger.debug("bomFeign.getBOMById={}", response+",bid="+bid);
        if (response.getCode().equals("200")) {
            ObjectMapper objectMapper = new ObjectMapper();
            bom = objectMapper.convertValue(response.getData(), BOM.class);
        }
        if(bom==null){
            throw new  RuntimeException();
        }
        int num = proCombineMapper.delDetail(proCombine.getCode());
        if(num==0){
            responseMsg.setCode("201");
            return responseMsg;
        }
        boolean flag = addDetail(proCombine,bom,map);
        if(flag){
            responseMsg.setCode("200");
        }else {
            responseMsg.setCode("201");
        }
        return responseMsg;
    }
private boolean addDetail(ProCombine proCombine,BOM bom,Map<String,Object> map){
    List<Integer> sids = proCombine.getSids();
    map.put("createUser",proCombine.getCreateUser());
    map.put("createDate",proCombine.getCreateDate());
    map.put("updateUser",proCombine.getUpdateUser());
    map.put("updateDate",proCombine.getUpdateDate());
    Good good = bom.getProduct();
    map.put("gid",good.getId());
    int sid = sids.get(0);
    map.put("sid",sid);
    int nu = proCombineMapper.addDetail(map);
    logger.debug("proCombineMapper addDetail nu:{}",nu+",map"+map);
    List<Good> list = bom.getMaterial();
    if(nu==0){
        return false;
    }
    for (int i=0;i<list.size();i++){
        good = list.get(i);
        map.put("gid",good.getId());
        sid = sids.get(i+1);
        map.put("sid",sid);
        nu = proCombineMapper.addDetail(map);
        logger.debug("proCombineMapper addDetail nu:{}",nu+",map"+map);
        if(nu==0){
            return false;
        }
    }
    return true;
}
    @Override
    public ResponseMsg delete(String code) {
        logger.info("ProCombineServiceImpl delete code={}", code);
        ResponseMsg responseMsg = new ResponseMsg();
        Map<String, Object> map = new HashMap<>();
        map.put("code", code);
        map.put("updateDate", new Date());
        map.put("updateUser", "123");
        int count = proCombineMapper.del(map);
        logger.debug("proCombineMapper.del count={}", count+",map="+map);
        if (count > 0) {
            int num = proCombineMapper.deleteDetail(map);
            logger.debug("proCombineMapper.deleteDetail num={}", num+",map="+map);
            if (num == 0) {
                responseMsg.setCode("201");
                return responseMsg;
            }
            responseMsg.setCode("200");
        }else {
            responseMsg.setCode("201");
        }
        return responseMsg;
    }

    @Override
    public ResponseMsg getByCode(String code) {
        logger.info("ProCombineServiceImpl getByCode code={}", code);
        ResponseMsg responseMsg = new ResponseMsg();
        ProCombine proCombine = proCombineMapper.getByCode(code);
        BOM bom = null;
        if (proCombine == null) {
            responseMsg.setCode("201");
            return responseMsg;
        }
        long id = proCombine.getBid();
        if (id != 0) {
            ResponseMsg response = bomFeign.getBOMById(id+"");
            logger.debug("bomFeign.getBOMById={}", response+",id="+id);
            if (response.getCode().equals("200")) {
                ObjectMapper objectMapper = new ObjectMapper();
                bom = objectMapper.convertValue(response.getData(), BOM.class);
            }
        }
        if (bom == null) {
            responseMsg.setCode("201");
            return responseMsg;
        }
        proCombine.setBom(bom);
        Map<String,Object> map = new HashMap<>();
        map.put("code", code);
        List<Integer> sids = new ArrayList<>();
        map.put("gid",bom.getProduct().getId());
        int sid = proCombineMapper.getSid(map);
        logger.debug("proCombineMapper.getSid={}", sid+",map="+map);
        if (sid == 0) {
            responseMsg.setCode("201");
            return responseMsg;
        }
        sids.add(sid);
        for (Good good : bom.getMaterial()) {
            map.put("gid",good.getId());
            sid = proCombineMapper.getSid(map);
            logger.debug("proCombineMapper.getSid={}", sid+",map="+map);
            if(sid==0){
                responseMsg.setCode("201");
            }
            sids.add(sid);
        }
        proCombine.setSids(sids);
        responseMsg.setCode("200");
        responseMsg.setData(proCombine);
        return responseMsg;
    }

    @Override
    public ResponseMsg changeStatus(String code, String status) {
        logger.info("ProCombineServiceImpl changeStatus code:{}", code);
        ResponseMsg responseMsg = new ResponseMsg();
        int count = proCombineMapper.changeStatus(code,status);
        logger.debug("proCombineMapper changeStatus count:{}", count+",code"+code);
        if(count>0){
            responseMsg.setCode("200");
        }else {
            responseMsg.setCode("201");
        }
        return responseMsg;
    }

    // 组装单转出库单
    @Override
    public OutStore createOutStoreFromProCombine(ProCombine combine) {
        OutStore outStore = new OutStore();
        // 1. 填充出库单基本信息
        Map<String,Object> map = new HashMap<>();
        map.put("docType","ZZCK");
        outStore.setCode(salesCounterFeign.addSalesCode(map).getData().toString()); // 生成出库单编号
        outStore.setOrderDate(combine.getDate());
        outStore.setSourceCode(combine.getCode()); // 来源单号
        outStore.setCid((int)combine.getUid()); // 客户ID或其他
        outStore.setDeptId((int)combine.getDid()); // 部门ID
        outStore.setStoreManId((int)combine.getSkid()); // 仓管员ID
        outStore.setTypeId(combine.getTypeId());
        outStore.setIsDelete(0);
        outStore.setCreateId((int)combine.getUid());
        outStore.setCreateName(combine.getCreateUser());
        outStore.setCreateDate(new Date());
        // 2. 创建出库明细列表
        List<OutStoreDetail> detailList = new ArrayList<>();
        List<Good> materials = combine.getBom().getMaterial();
        for (int i=0;i<materials.size();i++) {
            OutStoreDetail detail = new OutStoreDetail();
            detail.setOutStoreCode(outStore.getCode());
            detail.setGoodId(materials.get(i).getId());
            detail.setGoodsCode(materials.get(i).getCode());
            detail.setGoodsName(materials.get(i).getName());
            detail.setCount((int)(combine.getCount()));
            detail.setStoreId((int)combine.getSkid()); // 仓库ID
            detail.setStoreName(combine.getSkname());
            detail.setPrice(storeGoodSummaryMapper.selectKcStoreGoodBySidCid(detail.getStoreId(),detail.getGoodId()).getPrice());
            // 计算金额
            BigDecimal sumPrice = detail.getPrice().multiply(BigDecimal.valueOf(detail.getCount()));
            detail.setSumPrice(sumPrice);
            detail.setCreateId((int)combine.getUid());
            outStore.setCreateName(combine.getCreateUser());
            outStore.setCreateDate(new Date());
            detailList.add(detail);
        }
        saveOutStore(outStore, detailList);
        return outStore;
    }
    private void saveOutStore(OutStore outStore, List<OutStoreDetail> details) {
        int count =outStoreMapper.insertOutStore(outStore);
        logger.debug("proCombineMapper saveOutStore count:{}", count);
        if(count>0){
            for (OutStoreDetail detail : details) {
                int num = outStoreDetailMapper.insertOutStoreDetail(detail);
                logger.debug("proCombineMapper saveOutStoreDetail num:{}", num);
                if (num==0){
                    throw new RuntimeException();
                }
            }
        }else {
            throw new RuntimeException();
        }
    }
    // 组装单转入库单
    @Override
    public InStore createInStoreFromProCombine(ProCombine combine) {
        InStore inStore = new InStore();
        // 1. 生成入库单号
        Map<String,Object> map = new HashMap<>();
        map.put("docType", "ZZRK");
        String inCode = salesCounterFeign.addSalesCode(map).getData().toString();
        inStore.setCode(inCode);
        inStore.setOrderDate(combine.getDate());
        inStore.setSourceCode(combine.getCode());
        inStore.setPid((int) combine.getUid());
        inStore.setDeptId((int) combine.getDid());
        inStore.setStoreManId((int) combine.getSkid());
        inStore.setTypeId(combine.getTypeId());
        inStore.setOrderTypeId(combine.getTypeId());
        inStore.setIsDelete(0);
        inStore.setCreateId((int) combine.getUid());
        inStore.setCreateName(combine.getCreateUser());
        inStore.setCreateDate(new Date());
        List<InStoreDetail> detailList = new ArrayList<>();
        Good product = combine.getBom().getProduct();

        InStoreDetail detail = new InStoreDetail();
        detail.setInStoreCode(inCode);
        detail.setGoodId((int) product.getId());
        detail.setGoodsCode(product.getCode());
        detail.setGoodsName(product.getName());
        detail.setCount((int) combine.getCount());
        detail.setStoreId((int) combine.getSkid());
        detail.setStoreName(combine.getSkname());
        BigDecimal price = storeGoodSummaryMapper
                .selectKcStoreGoodBySidCid(detail.getStoreId(), detail.getGoodId())
                .getPrice();
        detail.setPrice(price);

        BigDecimal sumPrice = price.multiply(BigDecimal.valueOf(detail.getCount()));
        detail.setSumPrice(sumPrice);

        detail.setCreateId((int) combine.getUid());
        detail.setCreateName(combine.getCreateUser());
        detail.setCreateDate(new Date());

        detailList.add(detail);

        // 4. 保存入库单及明细
        saveInStore(inStore, detailList);
        return inStore;
    }

    private void saveInStore(InStore inStore, List<InStoreDetail> details) {
        int cnt = inStoreMapper.insertInStore(inStore);
        if (cnt <= 0) {
            throw new RuntimeException("入库单保存失败");
        }
        for (InStoreDetail d : details) {
            d.setInStoreCode(inStore.getCode());
            int n = inStoreDetailMapper.insertInStoreDetail(d);
            if (n <= 0) {
                throw new RuntimeException("入库明细保存失败");
            }
        }
    }

}
